package com.jl.magic.images;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.Arrays;

/**
 * @author jiangli
 * 图片像素操作
 */
public class PixelTools {

    /**
     * 根据像素值生成BufferedImage对象
     *
     * @param width  图片宽度
     * @param height 图片高度
     * @param pixels 像素值
     * @return BufferedImage对象
     */
    public static BufferedImage pixelsToImage(int[][] pixels, int width, int height) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int index = i * width + j;
                image.setRGB(j, i, BaseTools.pixel(pixels[index]));
            }
        }
        return image;
    }

    /**
     * 获取图片所有像素值
     *
     * @param image 图片文件
     * @return 所有像素rgb值
     */
    public static int[][] imageToPixels(BufferedImage image) {
        int[][] pixels;
        switch (image.getType()) {
            case BufferedImage.TYPE_3BYTE_BGR:
            case BufferedImage.TYPE_4BYTE_ABGR:
                pixels = getPixelsFast(image, 1, false);
                break;
            default:
                pixels = getPixelsSlow(image, 1, false);
                break;
        }
        return pixels;
    }

    /**
     * 提取图片像素，适用如下类型的图片
     * <p>
     *
     * @param sourceImage 图片文件
     * @param quality     分析提取图片像素的跨度，quality=1时，质量最高；
     *                    值越小质量越高，效率低；相反值越大提取像素越快，但也可能会造成颜色丢失。
     * @param ignoreWhite 是否忽略白色
     * @return 提取的像素点数组
     * @see BufferedImage#TYPE_3BYTE_BGR
     * @see BufferedImage#TYPE_4BYTE_ABGR
     */
    public static int[][] getPixelsFast(BufferedImage sourceImage, int quality, boolean ignoreWhite) {
        DataBufferByte dataBuffer = (DataBufferByte) sourceImage.getRaster().getDataBuffer();
        byte[] pixels = dataBuffer.getData();
        int pixelCount = sourceImage.getWidth() * sourceImage.getHeight();

        int colorDepth;
        int type = sourceImage.getType();
        switch (type) {
            case BufferedImage.TYPE_3BYTE_BGR:
                colorDepth = 3;
                break;
            case BufferedImage.TYPE_4BYTE_ABGR:
                colorDepth = 4;
                break;
            default:
                throw new IllegalArgumentException("未处理的图片类型: " + type);
        }

        int expectedDataLength = pixelCount * colorDepth;
        if (expectedDataLength != pixels.length) {
            throw new IllegalArgumentException("期望的像素数据长度(" + expectedDataLength + ") != 实际像素数据长度("
                    + pixels.length + ")");
        }

        if (quality > pixelCount) {
            throw new IllegalArgumentException("质量(quality)值超出了总像素范围");
        }

        //将rgb值存储到一个数组中,(pixelCount + quality - 1)防止数组出界
        int numRegardedPixels = (pixelCount + quality - 1) / quality;
        int numUsedPixels = 0;

        int[][] pixelArray = new int[numRegardedPixels][];
        int offset, a, r, g, b;

        switch (type) {
            case BufferedImage.TYPE_3BYTE_BGR:
                for (int i = 0; i < pixelCount; i += quality) {
                    offset = i * 3;
                    b = pixels[offset] & 0xFF;
                    g = pixels[offset + 1] & 0xFF;
                    r = pixels[offset + 2] & 0xFF;
                    //如果不为白色
                    boolean isWhite = ignoreWhite && r > 250 && g > 250 && b > 250;
                    if (!isWhite) {
                        pixelArray[numUsedPixels] = new int[]{r, g, b};
                        numUsedPixels++;
                    }
                }
                break;
            case BufferedImage.TYPE_4BYTE_ABGR:
                for (int i = 0; i < pixelCount; i += quality) {
                    offset = i * 4;
                    a = pixels[offset] & 0xFF;
                    b = pixels[offset + 1] & 0xFF;
                    g = pixels[offset + 2] & 0xFF;
                    r = pixels[offset + 3] & 0xFF;
                    //透明度>=125
                    boolean isWhite = ignoreWhite && r > 250 && g > 250 && b > 250;
                    if (a >= 125 && !isWhite) {
                        pixelArray[numUsedPixels] = new int[]{r, g, b};
                        numUsedPixels++;
                    }
                }
                break;
            default:
                throw new IllegalArgumentException("未处理的图片类型: " + type);
        }
        //删除pixelArray中空值的部分
        return Arrays.copyOfRange(pixelArray, 0, numUsedPixels);
    }

    /**
     * 提取图片像素，通过BufferedImage.getRGB()方法提取，比较慢，但适合大部分颜色类型的图片
     *
     * @param sourceImage 图片文件
     * @param quality     分析提取图片像素的跨度，quality=1时，质量最高；默认10；
     *                    值越小质量越高，效率低；相反值越大提取像素越快，但也可能会造成颜色丢失。
     * @param ignoreWhite 是否忽略白色
     * @return 提取的像素点数组
     */
    public static int[][] getPixelsSlow(BufferedImage sourceImage, int quality, boolean ignoreWhite) {
        int width = sourceImage.getWidth();
        int height = sourceImage.getHeight();

        int pixelCount = width * height;
        if (quality > pixelCount) {
            throw new IllegalArgumentException("质量(quality)值超出了总像素范围");
        }

        int numRegardedPixels = (pixelCount + quality - 1) / quality;
        int numUsedPixels = 0;

        int[][] res = new int[numRegardedPixels][];
        int r, g, b;

        for (int i = 0; i < pixelCount; i += quality) {
            int row = i / width;
            int col = i % width;
            int rgb = sourceImage.getRGB(col, row);

            r = (rgb >> 16) & 0xFF;
            g = (rgb >> 8) & 0xFF;
            b = (rgb) & 0xFF;
            if (!(ignoreWhite && r > 250 && g > 250 && b > 250)) {
                res[numUsedPixels] = new int[]{r, g, b};
                numUsedPixels++;
            }
        }

        return Arrays.copyOfRange(res, 0, numUsedPixels);
    }

}
